﻿//-----------------------------------------------------------------------
// <copyright file="AuthorizationServiceBase.Roles.cs" company="Alan Rodrigues">
//     Copyright (c) Alan Rodrigues. All rights reserved.
// </copyright>
// <developed>Alan Rodrigues (operninha@gmail.com)</developed>
//-----------------------------------------------------------------------

using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Linq;

namespace Authorization
{
    using System;
    using Properties;

    public partial class AuthorizationServiceBase
    {
        #region RoleAssignments

        public RoleAssignmentCollection GetAllRoleAssignments(string applicationName, string scopeName)
        {
            SecUtility.CheckParameter(ref applicationName, true, true, false, 64, "applicationName");

            var application = AuthorizationStoreManager.GetApplication(applicationName);
            if (application == null)
            {
                throw new AuthorizationException("AuthorizationService.GetAllRoleAssignments", Resources.invalid_application);
            }
            return application.GetRoleAssignments(scopeName);
        }

        /// <summary>
        /// Retorna o nome dos papeis do sistema
        /// </summary>
        /// <param name="applicationName">nome da Application</param>
        /// <param name="scopeName">Name do <seealso cref="Scope"/> onde será feita a busca dos papeis</param>
        /// <returns>Name dos papeis do Sistema</returns>
        public string[] GetAllRoleAssignmentNames(string applicationName, string scopeName)
        {
            SecUtility.CheckParameter(ref applicationName, true, true, false, 64, "applicationName");

            var  app = AuthorizationStoreManager.GetApplication(applicationName);
            
            if (app == null)
            {
                throw new AuthorizationException("AuthorizationService.GetAllRoleAssignmentNames", Resources.invalid_application);
            }

            return app.GetRoleAssignmentNames(scopeName);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="applicationName"></param>
        /// <param name="scopeName"></param>
        /// <param name="roleName"></param>
        /// <returns></returns>
        public bool RoleAssignmentExists(string applicationName, string scopeName, string roleName)
        {
            SecUtility.CheckParameter(ref applicationName, true, true, false, 64, "applicationName");
            SecUtility.CheckParameter(ref roleName, true, true, false, 64, "roleName");
            var app = AuthorizationStoreManager.GetApplication(applicationName);

            if (app == null)
            {
                throw new AuthorizationException("AuthorizationService.RoleAssignmentExists", Resources.invalid_application);
            }

            return app.RoleAssignmentExists(roleName, scopeName);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="applicationName"></param>
        /// <param name="scopeName"></param>
        /// <param name="roleAssignmentName"></param>
        /// <returns></returns>
        public RoleAssignment GetRoleAssignment(string applicationName, string scopeName, string roleAssignmentName)
        {
            SecUtility.CheckParameter(ref applicationName, true, true, false, 64, "applicationName");
            SecUtility.CheckParameter(ref roleAssignmentName, true, true, false, 64, "roleAssignmentName");

            var app = AuthorizationStoreManager.GetApplication(applicationName);

            if (app == null)
            {
                throw new AuthorizationException("AuthorizationService.GetRoleAssignment", Resources.invalid_application);
            }

            return app.GetRoleAssignment(roleAssignmentName, scopeName);
        }

        public RoleAssignment CreateRoleAssignment(string applicationName, string scopeName, string roleDefinitionName, string roleAssignmentName, string description)
        {
            SecUtility.CheckParameter(ref applicationName, true, true, false, 64, "applicationName");
            SecUtility.CheckParameter(ref roleAssignmentName, true, true, false, 64, "roleAssignmentName");
            SecUtility.CheckParameter(ref roleDefinitionName, true, true, false, 64, "roleDefinitionName");

            Application application = AuthorizationStoreManager.GetApplication(applicationName);

            if (application == null)
            {
                throw new AuthorizationException("AuthorizationService.CreateRoleAssignment", Resources.invalid_application);
            }
             
            var role = application.CreateRoleAssignment(roleAssignmentName, description, scopeName);
            role.AddRoleDefinition(roleDefinitionName);
            role.Save();
            return role;
        }

        public void DeleteRoleAssignment(string applicationName, string scopeName, string roleName)
        {
            SecUtility.CheckParameter(ref applicationName, true, true, false, 64, "applicationName");
            SecUtility.CheckParameter(ref roleName, true, true, false, 64, "roleName");

           var application = AuthorizationStoreManager.GetApplication(applicationName);

            if (application == null)
            {
                throw new AuthorizationException("AuthorizationService.DeleteRoleAssignment", Resources.invalid_application);
            }

            application.DeleteRoleAssignment(roleName, scopeName);
            application.Save();
        }

        public void UpdateRoleAssignment(string applicationName, string scopeName, string roleName, string newRoleName, string newDescription)
        {
            SecUtility.CheckParameter(ref applicationName, true, true, false, 64, "applicationName");
            SecUtility.CheckParameter(ref roleName, true, true, false, 64, "roleName");
            SecUtility.CheckParameter(ref newRoleName, true, true, false, 64, "newRoleName");

            var application = AuthorizationStoreManager.GetApplication(applicationName);

            if (application == null)
            {
                throw new AuthorizationException("AuthorizationService.UpdateRoleAssignment", Resources.invalid_application);
            }

            var role =  application.UpdateRoleAssignment(roleName, scopeName, newRoleName, newDescription);
            role.Save();
        }

        public void AddUsersToRoleAssignments(string applicationName, string scopeName, string[] SIDs, string[] roleNames)
        {
            SecUtility.CheckParameter(ref applicationName, true, true, false, 64, "applicationName");
            SecUtility.CheckArrayParameter(ref roleNames, true, true, false, 64, "roleNames");
            SecUtility.CheckArrayParameter(ref SIDs, true, true, false, 64, "SIDs");

            var application = AuthorizationStoreManager.GetApplication(applicationName);

            if (application == null)
            {
                throw new AuthorizationException("AuthorizationService.AddUsersToRoleAssignments", Resources.invalid_application);
            }

            foreach (var roleName in roleNames)
            {
                var role = application.GetRoleAssignment(roleName, scopeName);
         
                role.AddMembers(SIDs);
                role.Save();
            }
        }

        public void AddUserNamesToRoleAssignments(string applicationName, string scopeName, string[] usernames, string[] roleNames)
        {
            SecUtility.CheckParameter(ref applicationName, true, true, false, 64, "applicationName");
            SecUtility.CheckArrayParameter(ref roleNames, true, true, false, 64, "roleNames");
            SecUtility.CheckArrayParameter(ref usernames, true, true, false, 64, "usernames");

            var application = AuthorizationStoreManager.GetApplication(applicationName);

            if (application == null)
            {
                throw new AuthorizationException("AuthorizationService.AddUserNamesToRoleAssignments", Resources.invalid_application);
            }

            foreach (var roleName in roleNames)
            {
                var role = application.GetRoleAssignment(roleName, scopeName);
                if (role == null)
                    throw new AuthorizationException("AuthorizationService.AddUserNamesToRoleAssignments", string.Format(Resources.roleassignment_not_found, roleName));
                
                role.AddMemberNames(usernames);                
                role.Save();
            }
        }

        public string[] FindUsersInRoleAssignment(string usernameToMatch, string applicationName, string scopeName, string roleAssignmentName)
        {
            SecUtility.CheckParameter(ref applicationName, true, true, false, 64, "applicationName");
            SecUtility.CheckParameter(ref usernameToMatch, true, true, false, 64, "usernameToMatch");
            SecUtility.CheckParameter(ref roleAssignmentName, true, true, false, 64, "roleAssignmentName");
            var application = AuthorizationStoreManager.GetApplication(applicationName);

            if (application == null)
            {
                throw new AuthorizationException("AuthorizationService.FindUsersInRoleAssignment", Resources.invalid_application);
            }

            var role = application.GetRoleAssignment(roleAssignmentName, scopeName);
            var users =  role != null ? role.GetMembersName() : null;
          
            if (users == null)
                return null;

            var usersResult = new List<string>();
            
            var reg = new Regex(usernameToMatch);
            foreach (var user in users)
            {
                if (reg.IsMatch(user))
                     usersResult.Add(user);
                else if (IsUserInRoleAssignment(user, applicationName, scopeName, roleAssignmentName))
                      usersResult.Add(user);
            }

            return usersResult.ToArray();
        }

        public string[] GetUsersInRoleAssignment(string applicationName, string scopeName, string roleAssignmentName)
        {
            SecUtility.CheckParameter(ref applicationName, true, true, false, 64, "applicationName");
            SecUtility.CheckParameter(ref roleAssignmentName, true, true, false, 64, "roleAssignmentName");

            var application = AuthorizationStoreManager.GetApplication(applicationName);

            if (application == null)
            {
                throw new AuthorizationException("AuthorizationService.GetUsersInRoleAssignment", Resources.invalid_application);
            }

           
           var role =  application.GetRoleAssignment(roleAssignmentName, scopeName);
          
           return role != null ? role.GetMembersName() : null;
        }

        public void RemoveUsersFromRoleAssignments(string applicationName, string scopeName, string[] Sids, string[] roleAssignmentNames)
        {
            SecUtility.CheckParameter(ref applicationName, true, true, false, 64, "applicationName");
            SecUtility.CheckArrayParameter(ref Sids, true, true, false, 64, "Sids");
            SecUtility.CheckArrayParameter(ref roleAssignmentNames, true, true, false, 64, "roleAssignmentNames");

            var application = AuthorizationStoreManager.GetApplication(applicationName);

            if (application == null)
            {
                throw new AuthorizationException("AuthorizationService.RemoveUsersFromRoleAssignments", Resources.invalid_application);
            }
            foreach (var roleAssignmentName in roleAssignmentNames)
            {
                var role = application.GetRoleAssignment(roleAssignmentName, scopeName);
                if (role != null)
                {
                    role.DeleteMembers(Sids);
                    role.Save();
                }
            }
        }

        public void RemoveUserNameFromRoleAssignments(string applicationName, string scopeName, string[] usernames, string[] roleAssignmentNames)
        {
            SecUtility.CheckParameter(ref applicationName, true, true, false, 64, "applicationName");
            SecUtility.CheckArrayParameter(ref usernames, true, true, false, 64, "usernames");
            SecUtility.CheckArrayParameter(ref roleAssignmentNames, true, true, false, 64, "roleAssignmentNames");

            var application = AuthorizationStoreManager.GetApplication(applicationName);

            if (application == null)
            {
                throw new AuthorizationException("AuthorizationService.RemoveUsersFromRoleAssignments", Resources.invalid_application);
            }
            foreach (var roleAssignmentName in roleAssignmentNames)
            {
                var role = application.GetRoleAssignment(roleAssignmentName, scopeName);
                if ( role != null)
                {
                    role.DeleteMemberNames(usernames);
                    role.Save();
                }
            }
        }

        #region IM120338

        /// <summary>
        /// Realiza a remocao de todas as permissoes de um determinado usuario levando em conta
        /// os filtros informados.
        /// Jose Mauro - Rerum 18/05/2011 IM120338
        /// </summary>
        /// <param name="username">nome do usuario.</param>
        /// <param name="applicationName">nome das aplicacoes a serem consideradas.</param>
        /// <param name="scopeName">nome dos escopos a serem considerados.</param>
        /// <param name="roleAssignments">nome dos perfis que o usuario esta associado.</param>
        /// <returns></returns>
        public bool RemoveRoleAssignments(string username, string[] applicationName, string[] scopeName, string[] roleAssignments)
        {
            SecUtility.CheckParameter(ref username, true, true, false, 64, "username");

            /**
             * Caso nao tenha sido informado o nome das aplicacoes sao recuperadas todas as 
             * aplicacoes disponiveis. Caso contrario sao recuperadas todas as aplicacoes que
             * satisfacam os nomes fornecidos.
             */
            ApplicationCollection applications = null;
            if (applicationName == null || applicationName.Length == 0)
            {
                applications = GetAllApplications();
            }
            else
            {
                applications = new ApplicationCollection();
                applicationName.ToList().ForEach(new Action<string>(delegate(string appName)
                {
                    if (AuthorizationStoreManager.ApplicationExists(appName)) 
                        applications.Add(AuthorizationStoreManager.GetApplication(appName));                        
                }));   
            }

            if (applications != null)
            {
                foreach (Application app in applications)
                {
                    /**
                     * Com base nas aplicacoes obtidas sao recuperados os escopos da mesma. Caso
                     * tenha sido informado o nome dos escopos os mesmos serao recuperados, senao
                     * serao recuperados todos os escopos para a aplicacao corrente.
                     */ 
                    ScopeCollection scopes = null;
                    if (scopeName == null || scopeName.Length == 0)
                    {
                        scopes = app.GetScopes();
                        scopes.Add(null);
                    }
                    else
                    {
                        scopes = new ScopeCollection();
                        scopeName.ToList().ForEach(new Action<string>(delegate(string scpName)
                        {
                            if (string.IsNullOrEmpty(scpName)) scopes.Add(null);
                            else if (app.ScopeExists(scpName)) scopes.Add(app.GetScope(scpName));                            
                        }));
                    }

                    foreach (Scope scope in scopes)
                    {
                        /**
                         * Para cada escopo de uma determinada aplicacao sao recuperados todos os objetos
                         * RoleAssignment caso nao tenha sido informado o parametro roleAssignments. Caso
                         * contrario sao recuperado somente os que objetos que satisfacam o parametro recebido.
                         */
                        RoleAssignmentCollection roles = null;
                        RoleAssignmentCollection rolesRemove = null;
                        if (roleAssignments == null || roleAssignments.Length == 0)
                        {
                            roles = scope == null ? app.GetRoleAssignments(null) : scope.GetRoleAssignments(); 
                        }
                        else
                        {
                            roles = new RoleAssignmentCollection();
                            roleAssignments.ToList().ForEach(new Action<string>(delegate(string roleName)
                            {
                                if (app.RoleAssignmentExists(roleName, scope != null ? scope.Name : null))
                                    roles.Add(app.GetRoleAssignment(roleName, scope != null ? scope.Name : null));
                            }));
                        }

                        /**
                         * Para cada objeto RoleAssignment recuperado e verificado se o mesmo possui o usuario 
                         * recebido em seus membros. Caso o usuario esteja presente no grupo o objeto e acrescido 
                         * em uma lista para remocao.
                         */ 
                        if (roles != null)
                        {
                            rolesRemove = new RoleAssignmentCollection();
                            roles.ToList().ForEach(new Action<RoleAssignment>(delegate(RoleAssignment role)
                            {                                
                                if (role.GetMembersName().Contains(username)) rolesRemove.Add(role);
                            }));
                        }
                        if (rolesRemove != null)
                        {
                            rolesRemove.ToList().ForEach(new Action<RoleAssignment>(delegate(RoleAssignment role)
                            {
                                app.DeleteRoleAssignment(role.Name, scope != null ? scope.Name : null);
                            }));
                        }
                    }
                    // Salva as alteracoes na aplicacao corrente
                    app.Save();
                }
                return true;
            }
            return false;
        }

        /// <summary>
        /// Recupera todos os perfis que satisfacam os filtros recebidos.
        /// Jose Mauro - Rerum 18/05/2011 IM120338
        /// </summary>
        /// <param name="username">nome do usuario.</param>
        /// <param name="applicationName">nome das aplicacoes a serem consideradas.</param>
        /// <param name="scopeName">nome dos escopos a serem considerados.</param>
        /// <returns></returns>
        public RoleAssignmentUserCollection GetAllRoleAssignmentsByUser(string username, string[] applicationName, string[] scopeName)
        {
            RoleAssignmentUserCollection rolesUsers = new RoleAssignmentUserCollection(); // Objeto contendo as propriedades de retorno.
            /**
             * Caso nao tenha sido informado o nome das aplicacoes sao recuperadas todas as 
             * aplicacoes disponiveis. Caso contrario sao recuperadas todas as aplicacoes que
             * satisfacam os nomes fornecidos.
             */
            ApplicationCollection applications = null;
            if (applicationName == null || applicationName.Length == 0)
            {
                applications = GetAllApplications();
            }
            else
            {
                applications = new ApplicationCollection();
                applicationName.ToList().ForEach(new Action<string>(delegate(string appName)
                {
                    if (AuthorizationStoreManager.ApplicationExists(appName))
                        applications.Add(AuthorizationStoreManager.GetApplication(appName));
                }));
            }

            if (applications != null)
            {
                foreach (Application app in applications)
                {
                    /**
                     * Com base nas aplicacoes obtidas sao recuperados os escopos da mesma. Caso
                     * tenha sido informado o nome dos escopos os mesmos serao recuperados, senao
                     * serao recuperados todos os escopos para a aplicacao corrente.
                     */
                    ScopeCollection scopes = null;
                    if (scopeName == null || scopeName.Length == 0)
                    {
                        scopes = app.GetScopes();
                        scopes.Add(null);
                    }
                    else
                    {                        
                        scopes = new ScopeCollection();
                        scopeName.ToList().ForEach(new Action<string>(delegate(string scpName)
                        {
                            if (app.ScopeExists(scpName)) scopes.Add(app.GetScope(scpName));
                        }));
                    }

                    /**
                     * Com base nos escopos obtidos sao verificados todos os papeis vinculados ao mesmo. Para cada papel,
                     * recupera-se seus membros para verificar se dentre eles possuem um usuario que satisfaca o username
                     * fornecido. Caso o username nao tenha sido fornecido todas os membros sao atribuidos no retorno.
                     * Logo tem-se como retorno Quantidade_Aplicacoes X Quantidade_Escopos X Quantidade_Membros. Caso nao
                     * haja usuarios vinculadas a roleassigment corrente e retornado um registro sem usuario.
                     */ 
                    foreach (Scope scope in scopes)
                    {
                        RoleAssignmentCollection roles = scope == null ? app.GetRoleAssignments(null) : scope.GetRoleAssignments();
                        if (roles != null)
                        {
                            roles.ToList().ForEach(new Action<RoleAssignment>(delegate(RoleAssignment role)
                            {
                                string[] members = role.GetMembersName();
                                if (!string.IsNullOrEmpty(username))
                                {
                                    if (members != null && members.Contains(username)) rolesUsers.Add(new RoleAssignmentUser(username, app.Name, scope != null ? scope.Name : string.Empty, role.Name));
                                }
                                else if (members != null && members.Length > 0)
                                {
                                    members.ToList().ForEach(new Action<string>(delegate(string member)
                                    {
                                        rolesUsers.Add(new RoleAssignmentUser(member, app.Name, scope != null ? scope.Name : string.Empty, role.Name));
                                    }));
                                }
                                else
                                {
                                    rolesUsers.Add(new RoleAssignmentUser(string.Empty, app.Name, scope != null ? scope.Name : string.Empty, role.Name));
                                }
                            }));
                        }
                    }
                }
            }
            return rolesUsers;
        }

        #endregion

        #endregion
    }
}
